package cn.qiyu5522.tk_ems.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.qiyu5522.tk_ems.entity.*;
import cn.qiyu5522.tk_ems.entity.dto.DepartmentAndMajorMenuDTO;
import cn.qiyu5522.tk_ems.entity.dto.StudentDTO;
import cn.qiyu5522.tk_ems.entity.dto.StudentExcelDTO;
import cn.qiyu5522.tk_ems.entity.dto.QueryParamDTO;
import cn.qiyu5522.tk_ems.entity.vo.StudentVO;
import cn.qiyu5522.tk_ems.exception.BusinessException;
import cn.qiyu5522.tk_ems.mapper.*;
import cn.qiyu5522.tk_ems.result.CustomMapResult;
import cn.qiyu5522.tk_ems.result.R;
import cn.qiyu5522.tk_ems.retrofit.IdGeneratorApi;
import cn.qiyu5522.tk_ems.service.ClassroomService;
import cn.qiyu5522.tk_ems.service.DepartmentService;
import cn.qiyu5522.tk_ems.service.MajorService;
import cn.qiyu5522.tk_ems.service.StudentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Tonkey
 * @since 2023-02-03
 */
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {


    // 注入远程服务接口对象---id生成器
    @Resource
    private IdGeneratorApi idGeneratorApi;
    @Resource
    private MajorMapper majorMapper;
    @Resource
    private DepartmentMapper departmentMapper;
    @Resource
    private ClassroomMapper classroomMapper;
    @Resource
    private ObjectMapper objectMapper;
    @Resource
    private StudentService studentService;
    @Resource
    private ClassroomService classroomService;
    @Resource
    private MajorService majorService;
    @Resource
    private DepartmentService departmentService;
    @Resource
    private UserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleMapper roleMapper;


    /**
     * 批量添加
     *
     * @param studentList
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int saveMore(@Valid List<StudentVO> studentList) {
        // 待添加的学生信息集合
        List<Student> students = new ArrayList<>(studentList.size());
        Student student = null;
        User user = null;
        UserRole userRole = null;
        String type = "学生用户";
        for (StudentVO studentVo : studentList) {
            // 学号 由 年份后两位 + 院系编号 + 专业编号 + 数字 组成
            // 获取年份后两位
            String str = "";
            String year = String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
            str += year.substring(year.length() - 2);
            student = new Student();
            // 对象转换将VO类型转为实体类型
            BeanUtils.copyProperties(studentVo, student);
            // 拼接院系编号
            str += student.getDepartmentId();
            // 拼接专业编号
            str += student.getMajorId();
            // 调用远程服务获取id
            Long stuId = Long.valueOf(idGeneratorApi.getDefaultId(str));
            student.setId(stuId);
            students.add(student);

            // 向t_user 表中添加账号
            user  = new User();
            user.setId(student.getId());
            user.setName(student.getName());
            user.setUsername(String.valueOf(student.getId()));
            user.setPassword("111111");   // 默认密码
            user.setDescription(type); // 学生用户
            user.setState(0);
            user.setAvatar(student.getAvatar());
            userMapper.insert(user);
            // 查询学生角色的ID
            Role studentRole = roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getDescription, type));
            if(ObjectUtil.isEmpty(studentRole)){
                throw new BusinessException("角色表学生类型异常，请检查数据库");
            }
            // 向 user_role 关联表中添加信息
            userRole = new UserRole();
            userRole.setRoleId(studentRole.getId());
            userRole.setUserId(student.getId());
            userRoleMapper.insert(userRole);
        }
        // 执行添加操作并返回
        return baseMapper.insertBatchSomeColumn(students);
    }

    @Override
    public R queryStudentByPageCondition(QueryParamDTO<StudentVO> queryParamDTO) {
        // 取出条件查询的条件
        StudentVO condition = queryParamDTO.getCondition();
        // 查询学生表 获取学生信息
        IPage<Student> studentIPage = new Page<>(queryParamDTO.getCurrentPage(), queryParamDTO.getPageSize());
        LambdaQueryWrapper<Student> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 条件查询 不为空则带上，避免 NUll 异常
        if (ObjectUtil.isNotEmpty(condition)) {
            lambdaQueryWrapper.like(ObjectUtil.isNotEmpty(condition.getName()),
                            Student::getName, condition.getName())
                    .eq(ObjectUtil.isNotEmpty(condition.getId()), Student::getId, condition.getId())
                    .eq(ObjectUtil.isNotEmpty(condition.getDepartmentId()),
                            Student::getDepartmentId, condition.getDepartmentId())
                    .eq(ObjectUtil.isNotEmpty(condition.getMajorId()),
                            Student::getMajorId, condition.getMajorId())
                    .eq(ObjectUtil.isNotEmpty(condition.getClassroomId()),
                            Student::getClassroomId, condition.getClassroomId())
                    .orderByDesc(Student::getId);
        }
        baseMapper.selectPage(studentIPage, lambdaQueryWrapper);

        // 类转换对象
        // Student 转为 StudentDTO 对象
        List<StudentDTO> studentDTOS = objectMapper.convertValue(studentIPage.getRecords(), new TypeReference<List<StudentDTO>>() {
        });

        // 分别查询 班级表、专业表、院系表 的 id与编号
        Map<String, Object> threeTableQueryResultMap = this.getDepAndMajorAndClassRoomLists();
        List<Classroom> classrooms = (List<Classroom>) threeTableQueryResultMap.get("classrooms");
        List<Major> majors = (List<Major>) threeTableQueryResultMap.get("majors");
        List<Department> departments = (List<Department>) threeTableQueryResultMap.get("departments");

        studentDTOS.stream().forEach(studentDTO -> {
            // 设置班级
            if (CollectionUtil.isNotEmpty(classrooms)) {
                for (Classroom classroom : classrooms) {
                    if (classroom.getId().equals(studentDTO.getClassroomId())) {
                        studentDTO.setClassroom(classroom.getName());
                    }
                }
            }
            // 设置专业
            if (CollectionUtil.isNotEmpty(majors)) {
                for (Major major : majors) {
                    if (major.getId().equals(studentDTO.getMajorId())) {
                        studentDTO.setMajor(major.getName());
                    }
                }
            }
            // 设置部门
            if (CollectionUtil.isNotEmpty(departments)) {
                for (Department department : departments) {
                    if (department.getId().equals(studentDTO.getDepartmentId())) {
                        studentDTO.setDepartment(department.getName());
                    }
                }
            }
        });

        Map<String, Object> map = CustomMapResult.packagingResult(studentDTOS,
                queryParamDTO.getCurrentPage(),
                queryParamDTO.getPageSize(),
                studentIPage.getTotal());
        return R.ok().data("studentIPage", map);
    }

    public Map<String, Object> getDepAndMajorAndClassRoomLists() {
        Map<String, Object> map = new HashMap<>();
        // 查询【班级表】，获取全部班级信息
        List<Classroom> classrooms = classroomService.getForIdAndName();
//        QueryWrapper<Classroom> classroomQueryWrapper = new QueryWrapper<>();
//        classroomQueryWrapper.select("id", "name");
//        List<Classroom> classrooms = classroomMapper.selectList(classroomQueryWrapper);

        // 查询【专业表】，获取全部专业信息
        List<Major> majors = majorService.getForIdAndNameDepId();
//        QueryWrapper<Major> majorQueryWrapper = new QueryWrapper<>();
//        majorQueryWrapper.select("id", "name");
//        List<Major> majors = majorMapper.selectList(majorQueryWrapper);

        // 查询【院系表】，获取全部院系信息
        List<Department> departments = departmentService.getForIdAndName();
//        QueryWrapper<Department> departmentQueryWrapper = new QueryWrapper<>();
//        departmentQueryWrapper.select("id", "name");
//        List<Department> departments = departmentMapper.selectList(departmentQueryWrapper);

        map.put("classrooms", classrooms);
        map.put("majors", majors);
        map.put("departments", departments);
        return map;
    }

    @Override
    public R getDepAndMaJorAndClassroom() {
        QueryWrapper<Department> departmentQueryWrapper = new QueryWrapper<>();
        departmentQueryWrapper.select("id", "name");
        List<Department> departments = departmentMapper.selectList(departmentQueryWrapper);
        QueryWrapper<Major> majorQueryWrapper = new QueryWrapper<>();
        majorQueryWrapper.select("id", "name", "department_id");
        List<Major> majors = majorMapper.selectList(majorQueryWrapper);
        QueryWrapper<Classroom> classroomQueryWrapper = new QueryWrapper<>();
        majorQueryWrapper.select("id", "name", "major", "department_id");
        List<Classroom> classrooms = classroomMapper.selectList(classroomQueryWrapper);

        // 实际返回的集合
        List<DepartmentAndMajorMenuDTO> menuDTOS = new ArrayList<>(departments.size());
        // 存放子节点
        List<DepartmentAndMajorMenuDTO> children_major = null;
        List<DepartmentAndMajorMenuDTO> children_classroom = null;

        DepartmentAndMajorMenuDTO departmentNode = null;
        for (Department department : departments) {
            // 收集父节点信息
            departmentNode = new DepartmentAndMajorMenuDTO();
            departmentNode.setId(department.getId());
            departmentNode.setName(department.getName());
            departmentNode.setPid(0L);
            DepartmentAndMajorMenuDTO majorNode = null;
            children_major = new ArrayList<>();
            for (Major major : majors) {
                majorNode = new DepartmentAndMajorMenuDTO();
                if (department.getId().equals(major.getDepartmentId())) {
                    // 获取对应学院下的对应专业信息
                    majorNode.setId(major.getId());
                    majorNode.setName(major.getName());
                    majorNode.setPid(major.getDepartmentId());
                    DepartmentAndMajorMenuDTO classroomNode = null;
                    children_classroom = new ArrayList<>();
                    for (Classroom classroom : classrooms) {
                        // 获取专业下对应的班级
                        classroomNode = new DepartmentAndMajorMenuDTO();
                        if (classroom.getMajorId().equals(major.getId())) {
                            classroomNode.setId(classroom.getId());
                            classroomNode.setPid(classroom.getMajorId());
                            classroomNode.setName(classroom.getName());
                            children_classroom.add(classroomNode);
                        }
                        if (CollectionUtil.isEmpty(classroomNode.getChildren())) {
                            classroomNode.setChildren(null);
                        }
                    }
                    // 将班级加入专业节点
                    majorNode.setChildren(children_classroom);
                    if (CollectionUtil.isEmpty(majorNode.getChildren())) {
                        majorNode.setChildren(null);
                    }
                    children_major.add(majorNode);
                }
            }
            // 父节点设置子集合
            departmentNode.setChildren(children_major);
            if (CollectionUtil.isEmpty(departmentNode.getChildren())) {
                departmentNode.setChildren(null);
            }
            // 父节点存入集合中
            menuDTOS.add(departmentNode);
        }
        for (DepartmentAndMajorMenuDTO menuDTO : menuDTOS) {
            if (CollectionUtil.isEmpty(menuDTO.getChildren())) {
                menuDTO.setChildren(null);
            }
        }
        return R.ok().data("depAndMajorMenu", menuDTOS);
    }

    @Override
    public List<StudentExcelDTO> queryStudentListByIds(Long[] ids) {
        List<Student> studentList = null;
        if (ArrayUtil.isNotEmpty(ids)) {
            studentList = baseMapper.selectBatchIds(Arrays.asList(ids));
        } else {
            studentList = baseMapper.selectList(null);
        }

        // 类转换对象
        // Student 转为 StudentDTO 对象
        List<StudentExcelDTO> studentExcelDTOS = objectMapper.convertValue(studentList, new TypeReference<List<StudentExcelDTO>>() {
        });

        // 分别查询 班级表、专业表、院系表 的 id与编号
        Map<String, Object> threeTableQueryResultMap = this.getDepAndMajorAndClassRoomLists();
        List<Classroom> classrooms = (List<Classroom>) threeTableQueryResultMap.get("classrooms");
        List<Major> majors = (List<Major>) threeTableQueryResultMap.get("majors");
        List<Department> departments = (List<Department>) threeTableQueryResultMap.get("departments");

        studentExcelDTOS.stream().forEach(studentDTO -> {
            // 设置班级
            if (CollectionUtil.isNotEmpty(classrooms)) {
                for (Classroom classroom : classrooms) {
                    if (classroom.getId().equals(studentDTO.getClassroomId())) {
                        studentDTO.setClassroom(classroom.getName());
                    }
                }
            }
            // 设置专业
            if (CollectionUtil.isNotEmpty(majors)) {
                for (Major major : majors) {
                    if (major.getId().equals(studentDTO.getMajorId())) {
                        studentDTO.setMajor(major.getName());
                    }
                }
            }
            // 设置部门
            if (CollectionUtil.isNotEmpty(departments)) {
                for (Department department : departments) {
                    if (department.getId().equals(studentDTO.getDepartmentId())) {
                        studentDTO.setDepartment(department.getName());
                    }
                }
            }
        });

        return studentExcelDTOS;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R handleMapConvertAndSave(List<StudentExcelDTO> listByFile) {
        Map<String, Object> threeTableQueryResultMap = this.getDepAndMajorAndClassRoomLists();
        List<Classroom> classrooms = (List<Classroom>) threeTableQueryResultMap.get("classrooms");
        List<Major> majors = (List<Major>) threeTableQueryResultMap.get("majors");
        List<Department> departments = (List<Department>) threeTableQueryResultMap.get("departments");
        // 匹配各项 id
        listByFile.forEach(studentExcelDTO -> {
            classrooms.forEach(classroom -> {
                if (studentExcelDTO.getClassroom().equals(classroom.getName())) {
                    studentExcelDTO.setClassroomId(classroom.getId());
                }
            });
            majors.forEach(major -> {
                if (studentExcelDTO.getMajor().equals(major.getName())) {
                    studentExcelDTO.setMajorId(major.getId());
                }
            });
            departments.forEach(department -> {
                if (studentExcelDTO.getDepartment().equals(department.getName())) {
                    studentExcelDTO.setDepartmentId(department.getId());
                }
            });
        });
        // DTO转VO
        List<StudentVO> list = objectMapper.convertValue(listByFile, new TypeReference<List<StudentVO>>() {
        });

        // 调用saveMore 方法保存学生信息
        int i = studentService.saveMore(list);
        return i > 0 ? R.ok().message("导入成功") : R.error().message("导入失败");
    }

    @Override
    public R checkStudentIdIsExisting(Long studentId) {
        LambdaQueryWrapper<Student> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Student::getId, studentId);
        Student student = baseMapper.selectOne(lambdaQueryWrapper);

        return ObjectUtil.isNotEmpty(student) ?
                R.ok().data("flag", true).data("student", student).message("学号存在")
                :
                R.ok().data("flag", false).message("学号不存在");
    }

    @Override
    public R getStudentInfoById(Long studentId) {
        Student student = baseMapper.selectById(studentId);
        return R.ok().data("studentInfo",student);
    }

}
